<?php

namespace App\Support\CustomForm\Validate;

use App\Support\CustomForm\Helper\HelpTrait;
use App\Support\Facade\CustomerValidator;
use App\Support\Singleton\SingletonInstance;
use Closure;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;

class ValidateSupport extends SingletonInstance implements ValidateInterface
{

    use HelpTrait;

    const DATA_TYPE_STRING = "STRING";
    const DATA_TYPE_INT    = "INT";
    const DATA_TYPE_ARRAY  = "ARRAY";

    /**
     * @var array
     */
    protected array $exclude_eq;


    /**
     * 是否必填
     *
     * @var bool
     */
    protected bool $required = false;

    /**
     * 数据类型
     *
     * @var string
     */
    protected string $dataType;

    /**
     * 内容长度最小值
     *
     * @var int
     */
    protected int $min;

    /**
     * 内容长度最大值
     *
     * @var int
     */
    protected int $max;

    /**
     * 闭包校验
     *
     * @var Closure
     */
    protected Closure $closure;

    /**
     * in  校验
     *
     * @var array
     */
    protected array $in;


    /**
     * 时间校验规则
     *
     * @var string
     */
    protected string $dateRule;


    /**
     * @param bool $singleton
     * @return static
     */
    public static function getInstance(bool $singleton = false): self
    {
        return parent::getInstance($singleton); // TODO: Change the autogenerated stub
    }

    /**
     * @param bool $required
     * @return $this
     */
    public function setRequired(bool $required): ValidateSupport
    {
        $this->required = $required;
        return $this;
    }

    /**
     * @param string $dataType
     * @return $this
     */
    public function setDataType(string $dataType): ValidateSupport
    {
        $this->dataType = $dataType;
        return $this;
    }

    /**
     * @param int $min
     * @param int $max
     * @return ValidateSupport
     */
    public function setContentLength(int $min, int $max): ValidateSupport
    {
        return $this->setContentLengthMin($min)->setContentLengthMax($max);
    }

    /**
     * @param int $min
     * @return $this
     */
    public function setContentLengthMin(int $min): ValidateSupport
    {
        $this->min = $min;
        return $this;
    }

    /**
     * @param int $max
     * @return $this
     */
    public function setContentLengthMax(int $max): ValidateSupport
    {
        $this->max = $max;
        return $this;
    }

    /**
     * @param Closure $closure
     * @return $this
     */
    public function setClosure(Closure $closure): ValidateSupport
    {
        $this->closure = $closure;
        return $this;
    }


    /**
     * @param array $excludeEqParams
     * @return $this
     */
    public function setExcludeEq(array $excludeEqParams): ValidateSupport
    {

//        if (!empty($this->exclude_eq) && Str::startsWith($this->exclude_eq, "exclude_eq")) {
//            $this->exclude_eq .= ",{$field}-{$value}";
//        } else {
//            $this->exclude_eq = "exclude_eq:{$field}-{$value}";
//        }

        $this->exclude_eq = $excludeEqParams;
        return $this;
    }

    /**
     * @param array $in
     * @return $this
     */
    public function setIn(array $in): ValidateSupport
    {
        $this->in = $in;
        return $this;
    }

    /**
     * @param string $dateRule
     * @return $this
     */
    public function setDateRule(string $dateRule): ValidateSupport
    {
        $this->dateRule = sprintf("date_format:%s", $dateRule);
        return $this;
    }

    /**
     * @param $field
     * @param $value
     * @param array $extraParams
     * @param array $customAttributes
     * @param array $excludeRules
     * @throws ValidationException
     */
    public function validate(
        $field,
        $value,
        array $extraParams = [],
        array $customAttributes = [],
        array $excludeRules = []
    ) {
        $rules = array_merge(["bail"], $this->buildRules());

//        if (in_array($field, ["legalPersonBankCardFrontImg"])) {
//            var_dump([$field => $rules]);
//            die;
//        }

        // TODO: Implement validate() method.
        $validator = CustomerValidator::make(
            array_merge($extraParams, [
                $field => $value
            ]),
            [$field => $rules],
            [
                "{$field}.string" => ":attribute 数据类型需为字符串",
                "{$field}.int"    => ":attribute 数据类型需为字符串",
                "{$field}.array"  => ":attribute 数据类型需为数组"
            ],
            $customAttributes
        );

        $validator->setExcludeRules($excludeRules);

        if ($validator->fails()) {
            throw new ValidationException($validator);
        }
    }

    /**
     * @return array
     */
    public function buildRules(): array
    {
        $existsRules = get_object_vars($this);
        $rules       = [];
        collect($existsRules)->each(function ($ruleValue, $ruleKey) use (&$rules) {
            switch ($ruleKey) {
                case "required":
                    array_push($rules, $ruleValue ? "required" : "sometimes");
                    break;
                case "dataType":
                    array_push($rules, strtolower($ruleValue));
                    break;
                case "min":
                    array_push($rules, "min:{$ruleValue}");
                    break;
                case "max":
                    array_push($rules, "max:{$ruleValue}");
                    break;
                case "in":
                    array_push($rules, "in:" . implode(",", $ruleValue));
                    break;
                case "exclude_eq":
                    array_push($rules, "exclude_eq:" . serialize($ruleValue));
                    break;
                default:
                    array_push($rules, $ruleValue);
                    break;

            }
        });


        return $rules;
    }

    /**
     * 返回校验数据字段
     *
     * @return array
     */
    public function build(): array
    {
        return collect(get_object_vars($this))->only(["required", "min", "max"])->toArray();
    }

}
